<?php
/************************************
*   新浪相册 7.0
*   @file:data_model.php
*   @intro:数据库模型基类
*   @author:shaopu@
*   @date:Sun Sep 20 17:33:44 CST 2009
************************************/

/*
   数据模型类
   封装了一些SQL生成及数据库操作相关
   支持分库存贮 分表存贮
   内置了数据过滤，防止数据库注入
   内置了以记录状态标识代替删除操作
   
   可以进行链接操作 如: 
   $mod->start($uid)->set_id($uid)->fetch();
*/

//fetch_by_sql 方法中代替数据表名
define('K5_DATAMOD_TB' , 'K5_datamod_tbName');
define('K5_DATAMOD_NOHASH' , 0);

class lib_pdo_helper
{

    //db操作方法～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～
    /**
     * 插入一条记录
     *
     * @return bool
     */
    public function insert($pdo , $table , $array)
    {
        //值操作
        $sql_set = $this->make_set_sql($pdo , $array);
        //操作
        $sql = "INSERT INTO ".$table." SET ".$sql_set;
        $affect_rows = $pdo->exec($sql);
        
        
        if( !$rs || K5_DEBUG)
        {
        	$this->__log( __FUNCTION__.':'.TAB . $sql . (!$rs ? (TAB.$this->_db->error()):''));
            if(!$rs)
                return false;
        }
        
        return true;
    }
    
    public function replace()
    {
        //连接DB
        $rs = $this->_connect('m');//主库
        if(!$rs)
            return false;

        //表达式操作
        $sql_exp = '';
        if(count($this->_data_exped) > 0)
        {
            $arr_set_key = array_keys($this->_data_edited);
            $arr_exp_key = array_keys($this->_data_exped);
            if(count(array_intersect($arr_exp_key , $arr_set_key)) > 0)
            {
            	$this->__log( __FUNCTION__.':fields_error' , false);
                return false;
            }
                
            foreach ($this->_data_exped as $key => $exp)
                $arr_exp[] = $key." = ".$exp;
                
            $sql_exp = implode(' , ' , $arr_exp);
        }
        //值操作
        $sql_set = $this->_db->make_set_sql($this->_data_edited);
        //表达式操作与值操作的合并
        $sql_set = trim($sql_set .','. $sql_exp , ',');
        
        //操作
        $sql = "REPLACE INTO ".$this->_table." SET ".$sql_set.$sql_exp;
        $this->_append_sql_list($sql);
        $rs = $this->_db->query($sql);
        
        if( !$rs || K5_DEBUG)
        {
        	$this->__log( __FUNCTION__.':'.TAB . $sql . (!$rs ? (' '.$this->_db->error()):''));
            if(!$rs)
                return false;
        }
        
        return true;
    }
    /**
     * 更新记录
     *
     * @param string $extra_where 
     * @param int $limit
     * @return false or int(affected_rows)
     */
    public function update($extra_where = '' , $limit = null)
    {
        //连接DB
        $rs = $this->_connect('m');//主库
        if(!$rs)
            return false;
        
        //生成SQL表达式
        $sql_exp = '';
        $sql_set = '';
        
        if(count($this->_data_exped) > 0)
        {
            $arr_set_key = array_keys($this->_data_edited);
            $arr_exp_key = array_keys($this->_data_exped);
            if(count(array_intersect($arr_exp_key , $arr_set_key)) > 0)
            {
            	$this->__log( __FUNCTION__ . ':fields_error' , false);
                return false;
            }
                
            foreach ($this->_data_exped as $key => $exp)
                $arr_exp[] = $key." = ".$exp;
                
            $sql_exp = implode(' , ' , $arr_exp);
            
        }

        //生成赋值sql
        $sql_set = $this->_db->make_set_sql($this->_data_edited);
        $sql_set = $sql_set .','. $sql_exp;
        $sql_set = trim($sql_set , ',');
        
        $limit = $limit > 0 ? ' limit '.$limit : '';

        $sql = "UPDATE ".$this->_table." SET ".$sql_set.$this->_condition.($extra_where ? ' AND '.$extra_where:'').$limit;
        $this->_append_sql_list($sql);
        $rs = $this->_db->query($sql);
        if( !$rs || K5_DEBUG )
        {
        	$this->__log( __FUNCTION__ . ':'.TAB.$sql.(!$rs ? $this->_db->error():'') , $rs);
        }
        
        return $rs;
    }
    /**
     * 删除记录
     *
     * @param int $limit_n
     * @return bool
     */
    public function delete($limit_n = 0)
    {
        //连接DB
        $rs = $this->_connect('m');//主库
        if(!$rs)
            return false;
        
        $sql = "DELETE FROM ".$this->_table." ".$this->_condition;

        if($limit_n > 0)
            $sql .= " limit ".(int)$limit_n;

        $this->_append_sql_list($sql);
        $rs = $this->_db->query($sql);
        if(!$rs || K5_DEBUG)
        {
            $this->__log( __FUNCTION__ . ':'.TAB.$sql.(!$rs ? $this->_db->error():'') , $rs);
        }
        
        return $rs;
    }
    /**
     * 取单行数据
     *
     * @param null or array $fields 字段
     * @return bool
     */
    public function fetch($fields = null , $orderby = '')
    {
        //连接DB
        $rs = $this->_connect('s');//辅库
        if(!$rs)
            return false;
        
        //只能对单行操作
        $this->_is_mul = false;
            
        if(is_array($fields) && count($fields) > 0)
        {
            
            $sql_field = implode(',' , $fields);
        }
        else 
            $sql_field = '*';
        
        //构建SQL语句
        $sql = "SELECT ".$sql_field." FROM ".$this->_table . $this->_condition;
        if($orderby)
            $sql .= ' ORDER BY '.$orderby;
        $sql .= ' limit 1';
        
		
        $rs = $this->_db->get_row($sql , $data);
        if(!$rs || K5_DEBUG)
        {
        	$this->__log( __FUNCTION__ . ':'.TAB.$sql.(!$rs ? $this->_db->error() : '') , $rs);
        	if(!$rs)
                return false;
        }
        
        $this->_data = $data;
        
        return true;
    }
    /**
     * 取多行记录
     *
     * @param array $fields 字段
     * @param array $order　排序 
     * @param int $start
     * @param int $limit
     * @return bool
     */
    public function fetch_multi($fields = null , $orderby = '' , $start = 0 , $limit = 0)
    {
        //连接DB
        $rs = $this->_connect('s');//辅库
        if(!$rs)
            return false;
        
        $this->_is_mul = true;
        
        if(is_array($fields))
        {
                
            $sql_field = implode(',' , $fields);
        }
        else 
            $sql_field = '*';
        
        $sql_order = $orderby ? ' ORDER BY '.$orderby : '';
        
        if($limit > 0 && $start > 0)
            $sql_limit = ' LIMIT '.(int)$start . ' , ' . (int)$limit;
        elseif($limit > 0 && $start == 0)
            $sql_limit = ' LIMIT ' . (int)$limit;
        else
            $sql_limit = '';
            
        $sql = "SELECT ".$sql_field." FROM ".$this->_table . $this->_condition . $sql_order . $sql_limit;
        $rs = $this->_db->get_records($sql , $data);
        
        if(!$rs || K5_DEBUG)
        {
        	$this->__log( __FUNCTION__.':'.TAB.$sql.(!$rs ? $this->_db->error() : '') , $rs);
            if(!$rs)
                return false;
        }
        
        $n = $this->_db->num_rows();
        
        if($n < 1)
        {
        	$this->__log( __FUNCTION__ . ':null_result '.$sql);
            $this->count = 0;
            return true;
        }

        foreach ($data as $row)
        {
            $this->_data[] = $row;
        }
        $this->count = count($this->_data);
        $this->_pointer = 0;
        
        return true;
    }
    /**
     * 自定义SQL取数据
     * 注意：数据表名请使用常量 K5_DATAMOD_TB 代替，方法内部替换为真正的表名。
     *
     * @param string $sql
     * @return bool
     */
    public function fetch_by_sql($sql , $is_multi = false)
    {
        $this->_is_mul = $is_multi;
        //连接DB
        $rs = $this->_connect('s');//辅库
        if(!$rs)
            return false;
        
        if(!strpos($sql , K5_DATAMOD_TB))
        {
            $this->__log( __FUNCTION__ .TAB.':no tablename'.TAB.'sql:'.$sql , false);
            return false;
        }
        $sql = str_replace(K5_DATAMOD_TB , $this->_table , $sql);
        
        if($is_multi)
        {
            $rs = $this->_db->get_records($sql , $this->_data);
            $this->count = count($this->_data);
        }
        else 
            $rs = $this->_db->get_row($sql , $this->_data);
            
        if(!$rs || K5_DEBUG)
        {
            $this->__log( __FUNCTION__ . ':query_error sql:'.$sql.(!$rs? $this->_db->error():'') , $rs);
        }
        
        
        return true;
    }
    /**
     * 执行SQL
     * 注意：数据表名请使用常量 K5_DATAMOD_TB 代替，方法内部替换为真正的表名。
     *
     * @param string $sql
     * @param array $result
     * @param bool $is_write    //是否是写数据，此时需要连接主库
     * @return bool
     */
    public function query_sql($sql , $is_write)
    {
        //连接DB
        $rs = $this->_connect($is_write ? 'm' : 's');
        if(!$rs)
            return false;
        
    	if(!strpos($sql , K5_DATAMOD_TB))
        {
            $this->__log( __FUNCTION__ . ':no tablename sql:'.$sql , false);
            return false;
        }
        $sql = str_replace(K5_DATAMOD_TB , $this->_table , $sql);
        
        $rs = $this->_db->query($sql);
        if(!$rs || K5_DEBUG)
        {
        	$this->__log( __FUNCTION__ . ':query_error sql:'.$sql.(!$rs ? $this->_db->error():'') , $rs);
        	if(!$rs)
                return false;
        }
        return true;
    }
    /**
     * 取总记录数
     * 主要用于刚刚执行完的SELECT语句，直接使用之前定义的条件进行
     *
     * @param int $n
     * @return bool
     */
    public function fetch_count(&$n)
    {
        //连接DB
        $rs = $this->_connect('s');
        if(!$rs)
            return false;
            
        //取
        $sql = "SELECT count(*) FROM ".$this->_table.$this->_condition;
        $rs = $this->_db->get_var($sql , $n);
        
        if(!$rs || K5_DEBUG)
        {
        	$this->__log( __FUNCTION__ . ':'.$sql.(!$rs ? $this->_db->error():'') , $rs);
            if(!$rs)
                return false;
        }
        $this->count = $n;
        return true;
    }

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /**
     * 设置单值
     *
     * @param string $key 字段
     * @param mix $value　值
     * @return bool
     */
    public function set($key , $value = null)
    {
        $this->_data_edited[$key] = $value;
        return true;
    }
    /**
     * 设置表达式
     *
     * @param string $key 字段名
     * @param string $exp 表达式
     * @return bool
     */
    public function set_exp($key , $exp)
    {
        $this->_data_exped[$key] = $exp;
        return true;
    }
    /**
     * 批量设置值
     *
     * @param array $data
     * @return bool
     */
    public function set_array($data)
    {
        if(is_array($data) && count($data) > 0)
        {
            foreach ($data as $k => $v)
            {
                $this->_data_edited[$k] = $v;
            }
        }
    }
    /**
     * 取值
     *
     * @param string $key 字段名
     * @return false or string
     */
    public function get($key)
    {
        if(!$this->_is_mul)
        {
            return isset($this->_data_edited[$key])
                   ?$this->_data_edited[$key]
                   :$this->_data[$key];
        }
        else 
        {
            return $this->_data[$this->_pointer][$key];
        }
    }
    /**
     * 多条记录时 跳到下一条记录
     *
     * @return bool
     */
    public function next()
    {
        if(is_array($this->_data[$this->_pointer + 1]))
        {
            $this->_pointer++;
            return true;
        }
        return false;
    }
    /**
     * 多条记录时，回到第一条数据。
     *
     * @return bool
     */
    public function rewind()
    {
        $this->_pointer = 0;
        return true;
    }
    
    //~~常用方法~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /**
     * 返回数据
     *
     * @return array
     */
    public function get_data()
    {
        return $this->_data;
    }
    /**
     * 取查询结果集数
     *
     * @return int
     */
    public function get_num_rows()
    {
        return $this->_db->num_rows();
    }
	/**
	 * 获取 mysql_insert_id()
	 * @return int
	 */
	public function get_insert_id(){
		return $this->_db->insert_id();
	}
	/**
	 * 获取 mysql_affected_rows()
	 * @return int
	 */
	public function get_affected_rows(){
		return $this->_db->affected_rows();
	}
    /**
     * 取对应数组
     *
     * @param string $key_field
     * @param string $one_on_one_field
     * @return array
     */
    public function get_key2map($key_field = 'id' , $one_on_one_field = '')
    {
        if(!$this->_is_mul)
            return false;
            
        if($this->count < 1)
            return null;
            
         $arr_rs = array();
         $i = 0;
         foreach ( $this->_data as $row)
         {
             $key = $row[$key_field] ? $row[$key_field] : $i;
             $arr_rs[$key] = $one_on_one_field === '' ? $row : $row[$one_on_one_field];
             $i++;
         }
         return $arr_rs;
    }
    /**
     * 取LIMIT　START
     *
     * @param int $page
     * @param int $pagesize
     * @return int
     */
    public function get_limit_start($page , $pagesize)
    {
        return max(0 , ($page-1)*$pagesize);
    }
    
    //~~一些表达式生成方法~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    public function make_set_sql($pdo , $array)
    {
        $sql = '';
	    if(is_array($array) && count($array) > 0)
	    {
    	    foreach ($array as $k => $v)
    	    {
    	        $sql .= '`'.$k.'` = "'.$pdo->quote($v).'",'; //mysql全是字符串
    	    }
    	    $sql = rtrim($sql , ',');
	    }
	    return $sql;
    }
    public function make_in_sql($array)
    {
        return '"' . implode('","' , $array) . '"';
    }
    public function escape($str)
    {
        return $this->_db->escape($str);
    }
    
    /**
     * 生成三元表达式
     * ex: var = if(var == 1 , 0 , 1)
     *
     * @param unknown_type $if_field
     * @param unknown_type $if_value
     * @param unknown_type $value_true
     * @param unknown_type $value_false
     * @return unknown
     */
    public function _exp_if($if_field , $if_value , $value_true , $value_false , $operate = '=')
    {
        $operate = strtolower($operate);
        /*兼容　gt lt
        if(ctype_alpha($operate))
        {
            $translate = array(
                'gt' => '>',
                't' => '>',
                'gt' => '>',
                'gt' => '>',
            );
            $operate = strtr($operate , );
        }
        */
        return 'if(`'.$if_field.'`'.$operate.'"'.$if_value.'","'.$value_true.'","'.$value_false.'")';
    }
    /**
     * 记录LOG
     *
     * @param string $content
     * @param bool $error
     * @param string $suffix
     */
    private function __log($content , $suc = true , $suffix='')
    {
        $content = ($suc ? '' : K5_LOG_SIGN_ERROR.' ') . $content;
        K_log::debug($this->__log_dir, $content , $suffix );
    }   
    
}
?>